package it.uniba.di.mas.jpnde.gui;

import it.uniba.di.mas.jpnde.console.IConsoleBackEnd;
import it.uniba.di.mas.jpnde.console.IConsoleUI;
import it.uniba.di.mas.jpnde.core.PN;

import jade.util.leap.List;

import java.awt.Color;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;

import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.ListSelectionModel;
import javax.swing.table.AbstractTableModel;

public class ConsoleFrame extends JFrame 
	implements IConsoleUI{
	
	private static final long serialVersionUID = 1L;
	private IConsoleBackEnd beConsolle=null;
	
	private JTextField xmlFile=null;
	private JTextArea logTextArea=null;
	private JButton loadButton=null;
	private JButton startAllButton=null;
	private JButton stopAllButton=null;
	private JButton startButton=null;
	private JButton stopButton=null;
	private JButton clearButton=null;
	
	private JTable agentsTable=null;
	private AgentsTableModel agentsTableModel=null;

	public ConsoleFrame(IConsoleBackEnd beConsolle)
	{	
		super();
		
		int width=600;
		int height=700;
		Dimension d=Toolkit.getDefaultToolkit().getScreenSize();
		int scWidth=d.width;
		int scHeight=d.height;
		
		setBounds((scWidth-width)/2,(scHeight-height)/2,
					width,height);
		
		getContentPane().setLayout(null);
		
		this.beConsolle=beConsolle;
		
		JLabel lb1=new JLabel("PNML File:");
		lb1.setBounds(10,10,80,20);
		getContentPane().add(lb1);
		
		xmlFile=new JTextField();
		xmlFile.setBounds(75,10,470,20);
		xmlFile.setEditable(false);
		xmlFile.setBackground(Color.YELLOW);
		getContentPane().add(xmlFile);
		
		// File Chooser
		JButton bFileCh=new JButton("...");
		bFileCh.addActionListener(new ActionListener() {
			
			@Override
			public void actionPerformed(ActionEvent e) {
				// TODO Auto-generated method stub
				showFileChooser();
			}
			
		});
		bFileCh.setBounds(550,10,20,20);
		getContentPane().add(bFileCh);
		
		// Load Button
		loadButton=new JButton("Load");
		loadButton.addActionListener(new ActionListener() {
			
			@Override
			public void actionPerformed(ActionEvent e) {
				// TODO Auto-generated method stub
				loadXML();
			}
			
		});
		loadButton.setMnemonic(KeyEvent.VK_L);
		loadButton.setBounds(10,35,100,20);
		getContentPane().add(loadButton);
		
		// Agents Table
		agentsTable=new JTable();
		JScrollPane scrollTable = new JScrollPane(agentsTable);
		scrollTable.setBounds(10,60,570,155);
		agentsTableModel=new AgentsTableModel();
		agentsTable.setModel(agentsTableModel);
		agentsTable.setFillsViewportHeight(true);
		agentsTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); 
		getContentPane().add(scrollTable);
		
		
		// Start All Button
		startAllButton=new JButton("Start All");
		startAllButton.addActionListener(new ActionListener() {
			
			@Override
			public void actionPerformed(ActionEvent e) {
				// TODO Auto-generated method stub
				startAll();
			}
			
		});
		startAllButton.setMnemonic(KeyEvent.VK_S);
		startAllButton.setBounds(10,220,100,20);
		startAllButton.setEnabled(false);
		getContentPane().add(startAllButton);
		
		// Stop All Button
		stopAllButton=new JButton("Stop All");
		stopAllButton.addActionListener(new ActionListener() {
			
			@Override
			public void actionPerformed(ActionEvent e) {
				// TODO Auto-generated method stub
				stopAll();
			}
			
		});
		stopAllButton.setMnemonic(KeyEvent.VK_T);
		stopAllButton.setBounds(120,220,100,20);
		stopAllButton.setEnabled(false);
		getContentPane().add(stopAllButton);
		
		
		// Start Button
		startButton=new JButton("Start");
		startButton.addActionListener(new ActionListener() {
			
			@Override
			public void actionPerformed(ActionEvent e) {
				// TODO Auto-generated method stub
				start();
			}
			
		});
		startButton.setMnemonic(KeyEvent.VK_A);
		startButton.setBounds(230,220,100,20);
		startButton.setEnabled(false);
		getContentPane().add(startButton);
	
		// Stop Button
		stopButton=new JButton("Stop");
		stopButton.addActionListener(new ActionListener() {
			
			@Override
			public void actionPerformed(ActionEvent e) {
				// TODO Auto-generated method stub
				stop();
			}
			
		});
		stopButton.setMnemonic(KeyEvent.VK_O);
		stopButton.setBounds(340,220,100,20);
		stopButton.setEnabled(false);
		getContentPane().add(stopButton);
	
		
		
		// Clear Button
		clearButton=new JButton("Clear");
		clearButton.addActionListener(new ActionListener() {
			
			@Override
			public void actionPerformed(ActionEvent e) {
				// TODO Auto-generated method stub
				clear();
			}
			
		});
		clearButton.setMnemonic(KeyEvent.VK_C);
		clearButton.setBounds(450,220,100,20);
		clearButton.setEnabled(false);
		getContentPane().add(clearButton);
		
		// Text Area
		JScrollPane scrollPane=new JScrollPane(); 
		logTextArea=new JTextArea();
		scrollPane.setBounds(10,250,570,370);
		logTextArea.setEditable(false);
		scrollPane.setViewportView(logTextArea);
		getContentPane().add(scrollPane);
		
		// ClearLog Button
		JButton bClearLog=new JButton("Clear Log");
		bClearLog.addActionListener(new ActionListener() {
			
			@Override
			public void actionPerformed(ActionEvent e) {
				// TODO Auto-generated method stub
				logTextArea.setText("");
			}
			
		});
		bClearLog.setBounds(10,630,90,20);
		bClearLog.setMnemonic(KeyEvent.VK_C);
		getContentPane().add(bClearLog);
		
		setResizable(false);
		
		addWindowListener(
				new WindowAdapter() {
						public void windowClosing(WindowEvent e)
							{
								System.exit(0);
							}
					});
	}
	
	private void showFileChooser()
	{
		JFileChooser chooser = new JFileChooser();
		FileChooserFilter filter=new FileChooserFilter();
		filter.addExtension("pnml");
		
		chooser.setFileFilter(filter);
		int returnVal = chooser.showOpenDialog(this);
		
		if(returnVal == JFileChooser.APPROVE_OPTION) 
			{
				File file=chooser.getSelectedFile();
				xmlFile.setText(file.getAbsolutePath());
			}
		
	}
	
	private void loadXML() 
	{
		if (xmlFile.getText().trim().equals(""))
			{
			JOptionPane.showMessageDialog(null, 
					"Select PNML File !", 
					"Warning", 
					JOptionPane.WARNING_MESSAGE);
			return;
			}

		String sNomeFile=xmlFile.getText().trim();
		int iSizeNomeFile=sNomeFile.length();
		
		if ((iSizeNomeFile<5)||(!sNomeFile.substring(iSizeNomeFile-5).equalsIgnoreCase(".pnml")))
			{
			JOptionPane.showMessageDialog(null, 
					"PNML File is required !", 
					"Warning", 
					JOptionPane.WARNING_MESSAGE);
			return;		
			}	
		
		setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
		try {
			beConsolle.add(sNomeFile);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
			JOptionPane.showMessageDialog(null, 
					"Load PNML: "+e.getMessage(), 
					"Errore", 
					JOptionPane.ERROR_MESSAGE);
			return;
		}
		appendLogMessage("PNML File loaded");
		setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
	}
	
	@Override
	public void appendLogMessage(String message) {
		// TODO Auto-generated method stub
		logTextArea.append(message+"\n");
	}
	
	public void startAll() {
		setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
		try {
			beConsolle.startAll();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
			JOptionPane.showMessageDialog(null, 
					"Start: "+e.getMessage(), 
					"Errore", 
					JOptionPane.ERROR_MESSAGE);
			return;
		}
		setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
	}
	
	public void stopAll() {
		setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
		try {
			beConsolle.stopAll();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
			JOptionPane.showMessageDialog(null, 
					"Stop: "+e.getMessage(), 
					"Errore", 
					JOptionPane.ERROR_MESSAGE);
			return;
		}
		setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
	}
	
	public void start() {
		setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
		if (agentsTable.getSelectedRow()==-1)
			{
			JOptionPane.showMessageDialog(null, 
					"Select Petri Network !", 
					"Warning", 
					JOptionPane.WARNING_MESSAGE);
					setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
					return;
			}
		String netName=(String)agentsTableModel.getValueAt(agentsTable.getSelectedRow(),0);
		String id=(String)agentsTableModel.getValueAt(agentsTable.getSelectedRow(),1);
		if ((netName!=null)&&(!netName.equals(""))){
			id=JOptionPane.showInputDialog("Insert ID",id);
			if ((id!=null)&&(!id.equals(""))){
				// attivo start
				try {
					beConsolle.start(netName, id);
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
					setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
					JOptionPane.showMessageDialog(null, 
							"Start: "+e.getMessage(), 
							"Errore", 
							JOptionPane.ERROR_MESSAGE);
					return;
					}
				}
		}
			
		setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
	}
	
	public void stop() {
		setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
		if (agentsTable.getSelectedRow()==-1)
			{
			JOptionPane.showMessageDialog(null, 
					"Select Petri Network !", 
					"Warning", 
					JOptionPane.WARNING_MESSAGE);
					setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
					return;
			}
		String id=(String)agentsTableModel.getValueAt(agentsTable.getSelectedRow(),1);
		if ((id!=null)&&(!id.equals(""))){
			// attivo stop
			try {
				beConsolle.stop( id);
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
				JOptionPane.showMessageDialog(null, 
						"Stop: "+e.getMessage(), 
						"Errore", 
						JOptionPane.ERROR_MESSAGE);
				return;
				}
			}
		setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
	}
	
	
	public void clear() {
		setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
		try {
			beConsolle.clear();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
			JOptionPane.showMessageDialog(null, 
					"Clear: "+e.getMessage(), 
					"Errore", 
					JOptionPane.ERROR_MESSAGE);
			return;
		}
		setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
	}
	
	@Override
	public void managedPNsChange() {
		// TODO Auto-generated method stub
		List pns=beConsolle.getManagedPNs();
		boolean enableButton=true;
		boolean enableSingle=false;
		Object[][] values=new Object[pns.size()][5];
		for(int i=0;i<pns.size();i++)
			{
			values[i][0]=((PN)pns.get(i)).getNetId();
			values[i][1]=((PN)pns.get(i)).getId();
			values[i][2]=((PN)pns.get(i)).getState();
			values[i][3]=((PN)pns.get(i)).getAgentId();
			values[i][4]=((PN)pns.get(i)).getContainer();
			if (((PN)pns.get(i)).getState().equals(PN.STATE_RUNNING))
				enableButton=false;
			}
		if (pns.size()>0)
			enableSingle=true;
		agentsTableModel.setValues(values);
		startAllButton.setEnabled(enableButton);
		loadButton.setEnabled(enableButton);
		stopAllButton.setEnabled(!enableButton);
		startButton.setEnabled(enableSingle);
		stopButton.setEnabled(enableSingle);
		clearButton.setEnabled(enableButton);
	}
	
	class AgentsTableModel extends AbstractTableModel {
	    /**
		 * 
		 */
		private static final long serialVersionUID = 1L;
		private String[] columnNames = {"Petri Net","ID","State","Agent Manager","Container"};
	    private Object[][] data = new Object[0][0];

	    public int getColumnCount() {
	        return columnNames.length;
	    }

	    public int getRowCount() {
	        return data.length;
	    }

	    public String getColumnName(int col) {
	        return columnNames[col];
	    }
	  
	    public Object getValueAt(int row, int col) {
	        return data[row][col];
	    }

	    public boolean isCellEditable(int row, int col) {
	    	return false;
	    }

	    public void setValues(Object[][] values){
	    	data=values;
	    	this.fireTableDataChanged();
	    }
	   
	}

	
}
